<template>
  <view class="terminal-index" @click="globalTouth">
    <view class="terminal-top">
      <view @click="onSetting">
        {{ info?.name || "--" }}
        <span :style="{ color: online == '在线' ? '#41992d' : '#ff0000' }">
          ({{ online }})
        </span>
      </view>
      <g-button
        text="查看资质"
        color="#3d3d3d"
        size="18.75rpx"
        width="139rpx"
        padding="5rpx 0"
        background="#fff"
        @click="handleViewCredential"
      />
    </view>
    <Weather />
    <view class="terminal-content">
      <view class="terminal-take-box" @click="handleTake">
        <view>取药</view>
        <view class="btn-en">PICK UP MEDICINE</view>
      </view>
    </view>
    <view class="terminal-footer">
      <view>
        客服电话：{{ terminalInfo.service || "--" }} （在线时间：{{
          terminalInfo.onlineTime
        }}）
      </view>
      <view v-if="terminalInfo.permit"> 许可证 | {{ terminalInfo.permit || "--" }}</view>
      <view v-if="terminalInfo.address"> {{ terminalInfo.address || "--" }}</view>
    </view>
    <g-shadow ref="shadowRef" />
    <g-setting v-model="settingShow" @close="closeSetting" />
    <Supplement-dialog v-model:show="supplementShow" />
  </view>
</template>

<script setup lang="ts">
import { onMounted, ref, watch, computed } from "vue";
import { onLoad, onUnload } from "@dcloudio/uni-app";
import {
  getTerminalCabinet,
  getTerminal,
  saveHeartbeat,
  orderFeedback,
} from "@/request/api";
import { getDevicesPath } from "@/request/common";
import config from "@/request/baseUrl.js";
import Weather from "@/components/weather/index.vue";
import SupplementDialog from "@/components/SupplementDialog/index.vue";
// #ifdef APP-PLUS
const modbusrtu = uni.requireNativePlugin("modbusrtu");
const print = uni.requireNativePlugin("XXH-USB-PRINT"); // 小票打印机
// #endif

const info = ref<any>({
  // 机柜信息
  name: "",
});
const terminalInfo = ref<any>({}); // 终端信息
const protParam = ref<any>({}); // 串口参数
const socket = ref<any>({});
const wsId = ref<any>(); // websocket id
const isConnect = ref<boolean>(false); // 是否连接上
const timer = ref<any>(null); // 重连定时器
const devices = ref<any>([]); // 设备列表
const shadowRef = ref(); // 遮罩层
const clickNumber = ref<number>(0); // 点击次数
const clickTimer = ref<any>(null); // 点击定时器
const settingShow = ref<boolean>(false); // 设置弹窗
const serialNumber = ref<string>(""); // 序列号
const pullTimer = ref<number[]>([]); // 轮询定时器
const supplementShow = ref<boolean>(false); // 补货弹窗
const terminalStatus = ref<number>(0); // 终端状态
const autoReset = ref<boolean>(false); // 是否自动复位
const online = ref<string>("离线"); // PLC在线状态
const connectStatus = ref<boolean>(true); // 心跳websocket连接状态
const connectTimer = ref<any>(null); // 心跳websocket重连定时器

onMounted(() => {
  getTerminalInfo();
  // #ifdef APP-PLUS
  modbusrtu && modbusrtu.init();
  setInterval(async () => {
    const isOpen = await checkOpen();
    online.value = isOpen ? "在线" : "离线";
  }, 1000);
  // #endif
});

onLoad(() => {
  uni.$on("backHome", () => {
    globalTouth();
  });
  uni.$on("heart", (data: any) => {
    uploadHeart(data);
  });
  uni.$on("takeStatus", (val: number) => {
    terminalStatus.value = val;
  });
});

watch(terminalStatus, (val: number) => {
  if (val == 0) {
    checkAutoReset();
  }
});

watch(autoReset, (val: boolean) => {
  if (val) {
    checkAutoReset();
  }
});

// 检查是否自动复位
const checkAutoReset = () => {
  if (terminalStatus.value == 0 && autoReset.value) {
    checkIsOpen(async () => {
      let supp = await getSupplementStatus();
      if (!supp) {
        await handleReset();
      }
      autoReset.value = false;
    });
  }
};

// 打开设置弹窗
const onSetting = () => {
  clickNumber.value++;
  if (clickNumber.value >= 10) {
    settingShow.value = true;
    clickNumber.value = 0;
  }
  if (clickTimer.value) {
    clearTimeout(clickTimer.value);
  }
  clickTimer.value = setTimeout(() => {
    clickNumber.value = 0;
    clearTimeout(clickTimer.value);
    clickTimer.value = null;
  }, 1000);
};

// 关闭设置弹窗
const closeSetting = (val?: string) => {
  let serial = uni.getStorageSync("serialNumber"); // 获取序列号
  if (serial) {
    serialNumber.value = serial;
    if (!val) {
      // #ifdef APP-PLUS
      wsId.value = "";
      createWebSocket(true);
      // #endif
      // #ifdef H5
      getCabinetInfo(true);
      // #endif
    } else {
      // #ifdef APP-PLUS
      plus.runtime.restart();
      // #endif
    }
  } else {
    serialNumber.value = ""; // 清空序列号
    info.value.name = ""; // 清空机柜名称
    try {
      socket.value.close();
    } catch (e) {}
    isConnect.value = false; // 更新连接状态
  }
};

// 上传心跳数据
const uploadHeart = async (val: any) => {
  let status = 0;
  // #ifdef APP-PLUS
  let isOpen = await checkOpen();
  if (isOpen) {
    devices.value = await getDevicesPath(modbusrtu);
    if (devices.value.includes(protParam.value.com)) {
      status = 1;
    }
  }
  // #endif
  saveHeartbeat({
    cabinetId: info.value.id,
    humidity: val.humidity,
    temperature: val.temperature,
    sensorStatus: val.sensorStatus, // 温湿度传感器状态
    printerStatus: "", // 打印机状态
    status, // 控制器状态
  });
};

// 设置心跳
const setHeartbeat = () => {
  connectTimer.value = setInterval(async () => {
    if (connectStatus.value) {
      connectStatus.value = false;
      let sendData = {
        eventType: "COMMON",
        serialNumber: serialNumber.value,
        wsId: serialNumber.value,
        data: {
          eventType: "COMMON",
          timestamp: new Date().getTime(),
        },
      };
      sendSocket(sendData);
    } else {
      connectStatus.value = true;
      clearInterval(connectTimer.value);
      connectTimer.value = null;
      isConnect.value = false; // 更新连接状态
      createWebSocket(false);
    }
  }, 1000 * 50);
};

// 触发全局触摸事件
const globalTouth = () => {
  if (shadowRef.value) {
    shadowRef.value?.globalTouth();
  }
};

// 串口连接
const createProt = (reset = false) => {
  const { com, baudRate, stopBit, dataBits, checkBit, speed } = protParam.value;
  let config = {
    deviceName: com, // 串口地址
    baudRate, // 波特率
    stopBits: stopBit, //停止位
    dataBits, // 数据位
    parity: checkBit, // 校验位
  };
  // #ifdef APP-PLUS
  modbusrtu.connectToDevice(config, (str: string) => {
    checkIsOpen(
      async () => {
        sendCommand(3056, speed, 3058, (value: number | null) => {
          if (value == speed) {
            console.log("设置移动速度成功");
          }
        });
        // 是否在补药状态
        let supp = await getSupplementStatus();
        console.log("补药状态:", supp);
        supplementShow.value = supp;
        if (!supp && reset) {
          // 连接3秒后复位
          setTimeout(() => {
            checkIsOpen(async () => {
              await handleReset();
              sendEnd();
            });
          }, 3000);
        }
      },
      () => {
        console.log("重新连接");
        setTimeout(() => {
          createProt(false); // 重新连接
        }, 3000);
      }
    );
  });
  // #endif
};

// 初始化WebSocket连接
const createWebSocket = (reset = true) => {
  try {
    socket.value = uni.connectSocket({
      url: config.socketUrl + serialNumber.value,
      success: () => {
        console.log("WebSocket连接已创建");
        initWebSocket(reset);
      },
    });
  } catch (e) {
    console.error("创建WebSocket连接失败:", e);
    reConnect(); // 重连
  }
};

// 初始化WebSocket事件监听
const initWebSocket = (reset = true) => {
  socket.value.onOpen(() => {
    console.log("WebSocket连接已打开");
    getCabinetInfo(reset);
    isConnect.value = true; // 更新连接状态
    if (connectTimer.value) {
      clearInterval(connectTimer.value);
      connectTimer.value = null;
    }
    connectStatus.value = true;
    setHeartbeat(); // 设置心跳
  });

  // 监听WebSocket连接关闭事件
  socket.value.onClose(() => {
    console.log("WebSocket连接已关闭");
    isConnect.value = false; // 更新连接状态
    reConnect(); // 重连
  });

  // 监听WebSocket消息接收事件
  socket.value.onMessage(async (event: any) => {
    console.log("WebSocket接收到消息", event.data);
    let data = JSON.parse(event.data);
    let zStatus = 0; // z轴状态
    switch (data.eventType) {
      case "REAL_TIME_INFORMATION":
        // 实时信息
        // #ifdef APP-PLUS
        devices.value = await getDevicesPath(modbusrtu);
        // #endif
        console.log("设备列表：", devices.value);
        wsId.value = data.wsId;
        realTimeInfo(data);
        break;
      case "EDIT_PARAM":
        // 串口参数改变
        // #ifdef APP-PLUS
        let isOpen = await checkOpen();
        if (isOpen) modbusrtu.close();
        getCabinetInfo(true);
        // #endif
        break;
      case "RESET":
        // 手动复位
        checkIsOpen(async () => {
          await handleReset();
          sendEnd();
        });
        break;
      case "AUTO_RESET":
        // 自动复位
        autoReset.value = true;
        break;
      case "STOP":
        // 停止
        checkIsOpen(async () => {
          await handleStop();
          sendEnd();
        });
        break;
      case "PICK_UP_TEST":
        // 取药测试
        checkIsOpen(async () => {
          zStatus = (await readCommand(3026)) || 0;
          if (zStatus == 1) {
            await setZAxisUp(2);
            await handleStart();
          }
          for (const item of data.coordinateList) {
            await pickUp(item);
          }
          sendEnd();
        });
        break;
      case "PICK_UP":
        // 取药 + 卸货
        console.log("取药 + 卸货：", data);
        let orders = <any>[];
        let status = 1; // 1:成功 2:失败
        for (const item of data.coordinateList) {
          status = (await pickUp(item)) as number;
          orders.push({ ...item, status });
        }
        recordOrder({
          coordinateList: orders,
          orderId: data.orderId,
        });

        // let isTicket = await isAllowTicket();

        // #ifdef APP-PLUS
        if (print) {
          print.initUsbDevice(); // 初始化小票打印机
          setTimeout(() => {
            print.write(data.receiptStr); // 打印小票
          }, 10 * 1000);
        }
        // #endif
        await handleUnload();
        uni.$emit("takeResult", 2);
        sendEnd();
        break;
      case "MOVE":
        console.log("按方向移动：", data);
        // 按方向移动
        checkIsOpen(async () => {
          zStatus = (await readCommand(3026)) || 0;
          if (zStatus == 1) {
            await setZAxisUp(2);
            await handleStart();
          }
          if (data.direction == 1) {
            let now = (await readCommand(3032)) || 0;
            if (now - data.distance < 0) {
              sendMessage("WARN", "向上超出最小范围");
              sendEnd();
              return;
            } else {
              await setYAxis(now - data.distance);
            }
          } else if (data.direction == 2) {
            let now = (await readCommand(3030)) || 0;
            const { maxXAxis } = protParam.value;
            if (now + data.distance > maxXAxis) {
              sendMessage("WARN", "向右超出最大范围");
              sendEnd();
              return;
            } else {
              await setXAxis(now + data.distance);
            }
          } else if (data.direction == 3) {
            const { maxYAxis } = protParam.value;
            let now = (await readCommand(3032)) || 0;
            if (now + data.distance > maxYAxis) {
              sendMessage("WARN", "向下超出最大范围");
              sendEnd();
              return;
            } else {
              await setYAxis(now + data.distance);
            }
          } else if (data.direction == 4) {
            let now = (await readCommand(3030)) || 0;
            if (now - data.distance < 0) {
              sendMessage("WARN", "向左超出最小范围");
              sendEnd();
              return;
            } else {
              await setXAxis(now - data.distance);
            }
          }
          await handleStart();
          sendEnd();
        });
        break;
      case "MOVE_BY_COORDINATE":
        checkIsOpen(async () => {
          // 移动到指定坐标
          zStatus = (await readCommand(3026)) || 0;
          if (zStatus == 1) {
            await setZAxisUp(2);
            await handleStart();
          }
          await setXAxis(data.XAxis);
          await setYAxis(data.YAxis);
          await setZAxis(data.ZAxis);
          await handleStart();
          sendEnd();
        });
        break;
      case "EXTEND":
        // 设置正反面
        checkIsOpen(async () => {
          await setFace(data.face);
          await setZAxis(data.ZAxis);
          // 伸出Z轴
          zStatus = (await readCommand(3026)) || 0;
          await setZAxisUp(zStatus == 1 ? 2 : 1);
          await handleStart();
          sendEnd();
        });
        break;
      case "UNLOAD":
        // 卸货
        checkIsOpen(async () => {
          await handleUnload();
          sendEnd();
        });
        break;
      case "REFRESH":
        // 刷新状态 (未使用，执行的REAL_TIME_INFORMATION命令)
        break;
      case "HEARTBEAT":
        // 心跳检测
        uni.$emit("HEARTBEAT");
        checkIsOpen(() => {
          sendCommand(3038, 5, 3038, (value: number | null) => {
            if (value == 10) {
              sendMessage("SUCCESS", "心跳检测成功");
            }
          });
        });
        break;
      case "RESTART":
        // 重启(终端回到首页)
        // #ifdef APP-PLUS
        plus.runtime.restart();
        // #endif
        // #ifdef H5
        uni.reLaunch({ url: "/pages/index/index" });
        // #endif
        sendMessage("SUCCESS", "终端已重启");
        break;
      case "EDIT_EXPORT":
        // 设置卸货坐标
        checkIsOpen(async () => {
          await setUnloadXAxis(data.shipmentXAxis);
          await setUnloadYAxis(data.shipmentYAxis);
        });
        break;
      case "SUPPLEMENT_MEDICINE":
        // 补药
        checkIsOpen(async () => {
          supplementShow.value = true;
          await moveSupplement();
          sendMessage("SUCCESS", "补货已就位");
          sendEnd();
        });
        break;
      case "COMMON":
        connectStatus.value = true;
        break;
    }
  });

  // 监听WebSocket错误事件
  socket.value.onError((error: any) => {
    console.error("WebSocket发生错误:", error);
    isConnect.value = false; // 更新连接状态
    reConnect(); // 重连
  });
};

// 重连
const reConnect = () => {
  if (isConnect.value) return;
  if (socket.value) {
    console.log("正在重连...");
    if (timer.value) clearTimeout(timer.value);
    timer.value = setTimeout(() => {
      createWebSocket(false);
    }, 5000);
  }
};

// 发送提示消息
const sendMessage = (type: any, msg: string = "") => {
  let sendData = {
    eventType: "COMMON",
    serialNumber: serialNumber.value,
    wsId: wsId.value,
    data: {
      type,
      message: msg,
      success: true,
    },
  };
  sendSocket(sendData);
};

// 发送完成消息
const sendEnd = (result: boolean = true) => {
  let sendData = {
    eventType: "COMMON",
    serialNumber: serialNumber.value,
    wsId: wsId.value,
    data: {
      type: "COMPLETE",
      result,
    },
  };
  sendSocket(sendData);
};

// 获取实时信息
const realTimeInfo = async (data: any) => {
  let originalX: number | null = 0,
    originalY: number | null = 0,
    zAxisStatus: number | null = 0,
    shipmentXAxis: number | null = 0,
    shipmentYAxis: number | null = 0,
    zStatus: number | null = 0,
    alarm: any = {};

  // #ifdef APP-PLUS
  let isOpen = await checkOpen();
  if (isOpen) {
    originalX = await readCommand(3030);
    originalY = await readCommand(3032);
    zAxisStatus = await readCommand(3036);
    shipmentXAxis = await readCommand(3062);
    shipmentYAxis = await readCommand(3064);
    alarm = await getAlarmInfo();
    zStatus = alarm.pickUpEquipment;
  }
  // #endif
  let sendData = {
    serialNumber: serialNumber.value,
    eventType: data.eventType,
    wsId: wsId.value,
    data: {
      type: "REAL_TIME_INFORMATION",
      serialPortStatus: isOpen ? 1 : 0, // 串口状态
      kernelStatus: "", // DVP内核
      originalX: originalX, // 原始X轴坐标
      originalY: originalY, // 原始Y轴坐标
      shipmentXAxis: shipmentXAxis, // 卸货X轴坐标
      shipmentYAxis: shipmentYAxis, // 卸货Y轴坐标
      serialPortList: devices.value, // 串口号列表
      zaxisStatus: zStatus, // Z轴状态
      delay: new Date().getTime(), // 时间戳
      alarm: alarm, // 报警信息
    },
  };
  sendSocket(sendData);
};

// 记录订单
const recordOrder = (data: any) => {
  return new Promise(async (resolve) => {
    orderFeedback(data).then((res: any) => {
      resolve(res);
    });
  });
};

// 取药（不卸货）
const pickUp = (data: any) => {
  let result: number = 1;
  return new Promise(async (resolve) => {
    const { XAxis, YAxis, ZAxis, YAxisUp, face } = data;
    await setXAxis(XAxis);
    await setYAxis(YAxis);
    await setZAxis(ZAxis);
    await setYAxisUp(YAxis - YAxisUp);
    await setFace(face);
    await autoStart();
    let check = (await readCommand(3040)) || 0; // 检测是否取药成功
    if (check == 1) {
      // 取药失败, 再次取药
      await setZAxis(ZAxis);
      await setFace(face);
      await autoStart();
      let checkAgain = (await readCommand(3040)) || 0; // 重新取药
      if (checkAgain == 1) {
        result = 2;
      }
    }
    resolve(result);
  });
};

// 检测串口是否开启
const checkOpen = () => {
  return new Promise((resolve) => {
    // #ifdef APP-PLUS
    modbusrtu.checkConnection((str: string) => {
      let res = JSON.parse(str);
      if (res.code == 1 && res.data) {
        resolve(true);
      } else {
        resolve(false);
      }
    });
    // #endif
  });
};

// 检测串口是否开启(含回调)
const checkIsOpen = async (
  callback?: () => void,
  failCallback?: () => void
): Promise<void> => {
  try {
    const isOpen = await checkOpen();
    if (isOpen) {
      callback?.();
    } else {
      sendMessage("WARN", "串口未连接");
      failCallback?.();
    }
  } catch (error) {
    sendMessage("WARN", "检查串口状态时发生错误");
    failCallback?.();
  }
};

// 复位
const handleReset = () => {
  return new Promise((resolve) => {
    sendCommand(3004, 1, 3004, (value: number | null) => {
      if (value == 2) {
        console.log("开始复位");
        pollUntilReset(3004, 0, (final: number | null) => {
          supplementShow.value = false;
          sendMessage("SUCCESS", "复位结束");
          resolve(final);
        });
      }
    });
  });
};

// 停止
const handleStop = () => {
  return new Promise((resolve) => {
    sendCommand(3002, 1, 3002, (value: number | null) => {
      if (value == 2) {
        pollUntilReset(3002, 0, (final: number | null) => {
          if (final == 0) {
            pullTimer.value.forEach((i: any) => {
              clearTimeout(i);
            });
            pullTimer.value = [];
            sendMessage("SUCCESS", "停止成功");
          } else {
            sendMessage("WARN", "停止失败");
          }
          resolve(final);
        });
      }
    });
  });
};

// 是否可出小票
// const isAllowTicket = () => {
//   return new Promise((resolve) => {
//     pollUntilReset(3060, 1, (final: number | null) => {
//       resolve(final == 1);
//     });
//   });
// };

// 手动启动
const handleStart = () => {
  return new Promise((resolve) => {
    sendCommand(3000, 1, 3000, (value: number | null) => {
      if (value == 2) {
        pollUntilReset(3000, 0, (final: number | null) => {
          console.log("手动启动结束", final);
          resolve(final);
        });
      }
    });
  });
};

// 自动取药
const autoStart = () => {
  return new Promise((resolve) => {
    sendCommand(3012, 1, 3012, (value: number | null) => {
      if (value == 2) {
        pollUntilReset(3012, 0, (final: number | null) => {
          console.log("取药操作完成", final);
          resolve(final);
        });
      }
    });
  });
};

// 卸货
const handleUnload = () => {
  return new Promise((resolve) => {
    sendCommand(3014, 1, 3014, (value: number | null) => {
      if (value == 2) {
        pollUntilReset(3014, 0, (final: number | null) => {
          console.log("卸货成功", final);
          resolve(final);
        });
      }
    });
  });
};

// 设置正反面
const setFace = (val: number) => {
  return new Promise((resolve) => {
    sendCommand(3010, val, 3010, (value: number | null) => {
      if (value == (val == 1 ? 2 : 4)) {
        console.log("设置正反面成功", value);
        resolve(0);
      }
    });
  });
};

// 设置X轴
const setXAxis = (val: number) => {
  return new Promise((resolve) => {
    sendCommand(3006, val, 3030, (value: number | null) => {
      if (value == val) {
        resolve(value);
      }
    });
  });
};

// 设置Y轴
const setYAxis = (val: number) => {
  return new Promise((resolve) => {
    sendCommand(3008, val, 3032, (value: number | null) => {
      if (value == val) {
        resolve(value);
      }
    });
  });
};

// 设置Z轴
const setZAxis = (val: number) => {
  return new Promise((resolve) => {
    sendCommand(3034, val, 3036, (value: number | null) => {
      if (value == val) {
        resolve(value);
      }
    });
  });
};

// 伸出Z轴 / 收回Z轴
const setZAxisUp = (val: number) => {
  return new Promise((resolve) => {
    sendCommand(3086, val, 3086, (value: number | null) => {
      if (value == val) {
        console.log("伸出Z轴 / 收回Z轴成功", value);
        resolve(value);
      }
    });
  });
};

// 抬升Y轴
const setYAxisUp = (val: number) => {
  return new Promise((resolve) => {
    sendCommand(3080, val, 3080, (value: number | null) => {
      if (value == val) {
        resolve(value);
      }
    });
  });
};

// 设置下药点X轴
const setUnloadXAxis = (val: number) => {
  console.log("设置下药点X轴", val);
  return new Promise((resolve) => {
    sendCommand(3062, val, 3062, (value: number | null) => {
      if (value == val) {
        resolve(value);
      }
    });
  });
};

// 设置下药点Y轴
const setUnloadYAxis = (val: number) => {
  console.log("设置下药点Y轴", val);
  return new Promise((resolve) => {
    sendCommand(3064, val, 3064, (value: number | null) => {
      if (value == val) {
        resolve(value);
      }
    });
  });
};

// 补药移动机械臂
const moveSupplement = () => {
  return new Promise((resolve) => {
    sendCommand(3072, 1, 3072, (value: number | null) => {
      if (value == 1) {
        pollUntilReset(3072, 2, (final: number | null) => {
          console.log("补药成功", final);
          resolve(final);
        });
      }
    });
  });
};

// 获取补药状态
const getSupplementStatus = () => {
  return new Promise(async (resolve) => {
    let value = await readCommand(3072);
    resolve(value == 2);
  });
};

// 获取报警信息
const getAlarmInfo = () => {
  let alarmInfo = <any>{};
  return new Promise(async (resolve) => {
    alarmInfo.putMedicine = await readCommand(3016);
    alarmInfo.xAxisLeft = await readCommand(3018);
    alarmInfo.xAxisRight = await readCommand(3020);
    alarmInfo.yAxisUp = await readCommand(3022);
    alarmInfo.yAxisDown = await readCommand(3024);
    alarmInfo.pickUpEquipment = await readCommand(3026);
    alarmInfo.pickUpWindow = await readCommand(3028);
    resolve(alarmInfo);
  });
};

// 获取柜机信息
const getCabinetInfo = (reset = true) => {
  getTerminalCabinet(serialNumber.value).then(async (res: any) => {
    info.value = res.data;
    uni.setStorageSync("cabinet", res.data);
    protParam.value = res.data.cabinetParam;
    // #ifdef APP-PLUS
    devices.value = await getDevicesPath(modbusrtu);
    if (devices.value.includes(protParam.value.com)) {
      createProt(reset);
      setInterval(async () => {
        const isOpen = await checkOpen();
        if (!isOpen) {
          console.log("串口已断开, 重连");
          createProt(false);
        }
      }, 10 * 1000);
    }
    // #endif
  });
};

// 查看资质
const handleViewCredential = () => {
  if (serialNumber.value == "") {
    uni.showToast({
      title: "未绑定序列号",
      icon: "error",
    });
    return;
  }
  uni.navigateTo({
    url: "/pages/credential/index",
  });
};

// 写入指令
const sendCommand = (
  waddr: number,
  wval: number,
  raddr: number,
  callback?: (value: number | null) => void
) => {
  // #ifdef APP-PLUS
  modbusrtu.writeRegister(
    {
      slaveId: 2, // 从机地址
      address: waddr + 4096, // 寄存器地址
      value: wval, // 寄存器值
      writeTimeout: protParam.value.writeTimeout,
    },
    (str: string) => {
      let res = JSON.parse(str);
      if (res.code == 1) {
        readCommand(raddr).then((value) => {
          callback?.(value);
        });
      }
    }
  );
  // #endif
};

// 轮询
const pollUntilReset = (
  address: number,
  rval: number,
  callback?: (value: number | null) => void
) => {
  const MAX_ATTEMPTS = 240; // 最大尝试次数
  const POLL_INTERVAL = 500; // ms
  let count = 0;
  const checkValue = async () => {
    try {
      let value = await readCommand(address);
      if (value === rval) {
        callback?.(value);
      } else {
        count++;
        if (count < MAX_ATTEMPTS) {
          pullTimer.value[address] = setTimeout(checkValue, POLL_INTERVAL);
        } else {
          clearTimeout(pullTimer.value[address]);
          pullTimer.value[address] = null;
          callback?.(-1);
        }
      }
    } catch (err) {
      callback?.(-2);
    }
  };
  checkValue();
};

// 读取指令
const readCommand = (raddr: number): Promise<number | null> => {
  return new Promise((resolve) => {
    // #ifdef APP-PLUS
    modbusrtu.readHoldingRegisters(
      {
        slaveId: 2, // 从机地址
        address: raddr + 4096, // 寄存器地址
        quantity: 1, // 读取寄存器数量
        readTimeout: protParam.value.readTimeout,
      },
      (str: string) => {
        let res = JSON.parse(str);
        if (res.code == 1) {
          let list = JSON.parse(res.data);
          resolve(list[0]);
        } else {
          resolve(null);
        }
      }
    );
    // #endif
  });
};

// 发送数据
const sendSocket = (data: any) => {
  socket.value.send({
    data: JSON.stringify(data),
  });
};

// 取药
const handleTake = () => {
  if (serialNumber.value == "") {
    uni.showToast({
      title: "未绑定序列号",
      icon: "error",
    });
    return;
  }
  uni.navigateTo({
    url: "/pages/take/index",
  });
};

// 获取厂家信息
const getTerminalInfo = () => {
  let key = "mc_cabinet_manufacturer";
  getTerminal(key).then((res: any) => {
    terminalInfo.value = JSON.parse(res.data.value);
  });
};

onUnload(async () => {
  // 关闭WebSocket连接
  if (socket.value) {
    uni.closeSocket();
    socket.value = null;
    isConnect.value = false;
  }
  if (connectTimer.value) {
    clearInterval(connectTimer.value);
    connectTimer.value = null;
  }
  // 清除重连定时器
  if (timer.value) {
    clearTimeout(timer.value);
    timer.value = null;
  }
  // 清除轮询定时器
  pullTimer.value.forEach((i: any) => {
    clearTimeout(i);
  });
  pullTimer.value = [];

  // #ifdef APP-PLUS
  let isOpen = await checkOpen();
  if (isOpen) modbusrtu.close();
  // #endif
  uni.$off("backHome");
});
</script>

<style lang="scss" scoped>
.terminal-index {
  height: 100vh;
  width: 100vw;
  position: relative;
  background: url("../../static/home.png") no-repeat;
  background-size: 100% 100%;
  padding-top: 34.75rpx;
  box-sizing: border-box;
  .terminal-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: #c8df8f;
    margin-right: 50rpx;
    padding: 4rpx 20rpx;
    border-top-right-radius: 50rpx;
    border-bottom-right-radius: 50rpx;
    view {
      font-size: 26.25rpx;
      height: 40rpx;
      font-family: Source Han Sans;
      font-weight: 700;
      color: #41992d;
      padding: 12rpx;
      width: 80%;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
  }
  .terminal-content {
    display: flex;
    justify-content: flex-end;
    padding: 0 20rpx;
    .terminal-take-box {
      width: 387.5rpx;
      height: 193rpx;
      background: url("../../static/take-bg.png") no-repeat;
      background-size: 100% 100%;
      position: relative;
      padding: 40rpx 80rpx;
      box-sizing: border-box;
      font-family: Source Han Sans;
      font-weight: 700;
      font-size: 34rpx;
      color: #41992d;
      line-height: 50rpx;
      .btn-en {
        font-family: Source Han Sans;
        font-weight: 400;
        font-size: 14rpx;
        color: #41992d;
        line-height: 19rpx;
      }
      &::after {
        content: "";
        position: absolute;
        top: 30rpx;
        right: 54rpx;
        width: 86.25rpx;
        height: 86.25rpx;
        background: url("../../static/take.png") no-repeat;
        background-size: 100% 100%;
        z-index: 1;
      }
      &:active {
        opacity: 0.8;
      }
    }
  }
  .terminal-footer {
    position: fixed;
    bottom: 40rpx;
    left: 40rpx;
    right: 40rpx;
    // height: 115.625rpx;
    background: linear-gradient(
      180deg,
      rgba(231, 247, 189, 0.496) 0%,
      rgba(200, 223, 143, 0.8) 100%
    );
    box-shadow: inset 0 2rpx 10rpx 0 rgba(149, 131, 16, 0.3);
    border-radius: 25rpx;
    backdrop-filter: blur(6rpx);
    padding: 18rpx 30rpx;
    box-sizing: border-box;
    view {
      font-family: Source Han Sans;
      font-weight: 400;
      font-size: 18rpx;
      color: #3d3d3d;
      line-height: 28rpx;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
}
</style>
